﻿/*
 * Created by SharpDevelop.
 * User: Corrado Mio
 * Date: 23/06/2012
 * Time: 07:07
 * 
 * 
 */
using System;
using System.Collections.Generic;
using BAPool = System.Collections.Generic.Dictionary<int, System.Collections.Generic.Queue<byte[]>>;

namespace CSharpExt.Collections
{
    /// <summary>
    /// La classe mette a disposizione un meccanismo efficiente per allocare dei buffer, 
    /// utilizzarli e rilasciarli.
    /// 
    /// I buffer vengono allocato con dimensioni multiple di 1024 (o 512?) byte, per ridurre la
    /// frammentazione.
    /// 
    /// Puo' essere allocato buffer di dimensione massima 2GB
    /// 
    /// E' possibile indicare ogni quanto tempo vuotare la cache dei bytearray allocati e poi
    /// rilasciati. Non e' necessario l'uso di un thread dedicato. E' sufficiente testare
    /// il timestamp dell'ultima allocazione sullesulle release 
    /// </summary>
    public static class ByteArrays
    {
        #region Private Data & Implementation
        
        private static int MINALLOC = 512;
        
        private static int _clearTimeout = 0;//10*60*1000;
        
        private static int _lastClear = Environment.TickCount;
        
        private static Queue<byte[]>[] _buckets = new Queue<byte[]>[32];
        
        private static Queue<byte[]> getQueue(int length)
        {
            int n=0, l=512;
            while(l<length)
            {
                n++;
                l+=l;
            }
            Queue<byte[]> q;
            if ((q = _buckets[n]) == null)
            {
                _buckets[n] = q = new Queue<byte[]>();
            }
            return q;
        }
        
        #endregion
        
        #region Properties
        
        public static int ClearTimeot
        {
            set { _clearTimeout = value; }
        }
        
        #endregion
        
        #region Operations
        
        public static byte[] Allocate(int length)
        {
            length = MINALLOC*((length + MINALLOC - 1)/MINALLOC);
            
            lock (_buckets)
            {
                Queue<byte[]> q = getQueue(length);
                
                if (q.Count == 0)
                    return new byte[length];
                else
                    return q.Dequeue();
            }
        }
        
        public static void Release(byte[] buffer)
        {
            lock (_buckets)
            {
                Queue<byte[]> q = getQueue(buffer.Length);
                q.Enqueue(buffer);
                
                if (_clearTimeout != 0 && Environment.TickCount - _lastClear > _clearTimeout)
                {
                    _lastClear = Environment.TickCount;
                    _buckets = new Queue<byte[]>[10];
                }
                    
            }
        }
        
        #endregion
    }
}
